#include <iostream>
#include <type_traits>
#include <memory>

using namespace std;

class Foo{
    public:
        Foo() {
            cout << "Construct" << endl;
        }
        ~Foo(){
            cout << "Descontruct" << endl;
        }

        Foo& operator=(const Foo & ) {
            cout << "operator= Construct" << endl;
        }

        Foo(const Foo & ) {
            cout << "lvalue" << endl;
        }

        Foo(const Foo && ) {
            cout << "rvalue" << endl;
        }

};

template<class T>
struct Construct{
    typedef typename std::remove_reference<T>::type U; //移除可能的引用

    Construct():m_ptr(new U) {}

    typename std::add_lvalue_reference<U>::type //添加左值引用
        Get() const 
        {
            return * m_ptr.get();
        }
    T Get2() const  //会多调用一次 拷贝构造和一次析构
        {
            return * m_ptr.get();
        }

    private:
    std::unique_ptr<U> m_ptr;
};

//cannot convert 'U* {aka std::remove_cv<Foo>*}' to 'std::remove_cv<Foo>::type* {aka Foo*}' in return
template<typename T>
typename std::remove_cv<typename std::remove_reference<T>::type>::type* 
Create()
{
    typedef typename std::remove_cv<typename std::remove_reference<T>::type> U;
    return new U();
}

template<typename T>
typename std::decay<T>::type* Create2()
{
    typedef typename std::decay<T>::type U;
    return new U();
}

template<typename F>
struct SimapleFunction{
    using FnType = typename std::decay<F>::type;
    SimapleFunction(F &f) : m_fn(f)
    {}

    void Run()
    {
        m_fn();
    }

    FnType m_fn;
};

//如果要保存输入的函数，则先要保存函数对象的函数指针类型，这是就可以用`std::decay` 
//来获取函数指针类型了， `using FnType = typename std::decay<F>::type;` 
                    //实现函数指针类型的定义



int main(void)
{
    Construct<int> c;
    int a = c.Get2();
    cout << a << endl;

    Construct <Foo> f;
    f.Get2();


    //int *p = Create<const int&>();
    //Create<int &>();
    //
    //
    Create2<Foo>();


    //根据条件选择的traits
    typedef std::conditional<(sizeof(long long) > sizeof(long double)),
            long long, 
            long double>::type max_size_t;

    cout << typeid(max_size_t).name() << endl;


    //能够不做任何评价和判断，将注意力集中在当前的事情上
    return 0;
}


//在上述代码中，构造对象时需要创建一个智能指针，创建智能指针需要获取T 的原始类型，
//我们通过`std::remove_reference`来移除 T可能的引用， 后面，需要获取智能指针的对象时，又要对原始类型添加左值引用
